// Package pay_api provides agent management functionality for payment operations.
package pay_api

import (
	"context"

	"github.com/gogf/gf/v2/frame/g"
)

// AgentService provides agent management operations
type AgentService struct {
	client ClientInterface
}

// NewAgentService creates a new agent service instance
func NewAgentService(client ClientInterface) *AgentService {
	return &AgentService{
		client: client,
	}
}

// CreateAgent creates a new agent
func (s *AgentService) CreateAgent(ctx context.Context, secret Secret, agentInfo AgentInfo) (*AgentInfo, error) {
	if err := s.validateAgentInfo(agentInfo); err != nil {
		return nil, err
	}

	reqData := g.Map{
		"agentInfo": s.agentInfoToMap(agentInfo),
	}

	// Set authentication headers
	client := s.client.(*Client)
	client.client.SetHeaderMap(g.MapStrStr{
		"grpc-app-username": secret.Username,
		"grpc-app-key":      secret.Key,
	})

	resp, err := s.client.DoRequest(ctx, "POST", AgentCreateEndpoint, reqData)
	if err != nil {
		return nil, NewPayAPIErrorWithDetails(ErrAPIError, "创建代理商失败", err.Error())
	}

	var result AgentAdminResponse
	if err := resp.Scan(&result); err != nil {
		return nil, NewPayAPIErrorWithDetails(ErrResponseParsing, "解析响应失败", err.Error())
	}

	if result.Code != 0 {
		return nil, NewPayAPIError(ErrAPIError, result.Message)
	}

	return result.AgentInfo, nil
}

// UpdateAgent updates an existing agent
func (s *AgentService) UpdateAgent(ctx context.Context, secret Secret, agentInfo AgentInfo) error {
	if err := s.validateAgentInfo(agentInfo); err != nil {
		return err
	}

	reqData := g.Map{
		"agentInfo": s.agentInfoToMap(agentInfo),
	}

	// Set authentication headers
	client := s.client.(*Client)
	client.client.SetHeaderMap(g.MapStrStr{
		"grpc-app-username": secret.Username,
		"grpc-app-key":      secret.Key,
	})

	resp, err := s.client.DoRequest(ctx, "POST", AgentUpdateEndpoint, reqData)
	if err != nil {
		return NewPayAPIErrorWithDetails(ErrAPIError, "更新代理商失败", err.Error())
	}

	var result CommonRes[interface{}]
	if err := resp.Scan(&result); err != nil {
		return NewPayAPIErrorWithDetails(ErrResponseParsing, "解析响应失败", err.Error())
	}

	if result.Code != 0 {
		return NewPayAPIError(ErrAPIError, result.Message)
	}

	return nil
}

// GetAgent retrieves agent information
func (s *AgentService) GetAgent(ctx context.Context, secret Secret, agentId string) (*AgentInfo, error) {
	if agentId == "" {
		return nil, NewPayAPIError(ErrInvalidRequest, "代理商ID不能为空")
	}

	reqData := g.Map{
		"agentId": agentId,
	}

	// Set authentication headers
	client := s.client.(*Client)
	client.client.SetHeaderMap(g.MapStrStr{
		"grpc-app-username": secret.Username,
		"grpc-app-key":      secret.Key,
	})

	resp, err := s.client.DoRequest(ctx, "POST", AgentGetEndpoint, reqData)
	if err != nil {
		return nil, NewPayAPIErrorWithDetails(ErrAPIError, "获取代理商信息失败", err.Error())
	}

	var result AgentAdminResponse
	if err := resp.Scan(&result); err != nil {
		return nil, NewPayAPIErrorWithDetails(ErrResponseParsing, "解析响应失败", err.Error())
	}

	if result.Code != 0 {
		return nil, NewPayAPIError(ErrAPIError, result.Message)
	}

	return result.AgentInfo, nil
}

// Helper methods
func (s *AgentService) validateAgentInfo(agentInfo AgentInfo) error {
	if agentInfo.AgentId == "" {
		return NewPayAPIError(ErrInvalidRequest, "代理商编号不能为空")
	}
	if agentInfo.Name == "" {
		return NewPayAPIError(ErrInvalidRequest, "代理商名称不能为空")
	}
	return nil
}

func (s *AgentService) agentInfoToMap(agentInfo AgentInfo) g.Map {
	return g.Map{
		"id":                agentInfo.Id,
		"agentId":           agentInfo.AgentId,
		"name":              agentInfo.Name,
		"contact":           agentInfo.Contact,
		"phone":             agentInfo.Phone,
		"email":             agentInfo.Email,
		"address":           agentInfo.Address,
		"status":            agentInfo.Status,
		"createTime":        agentInfo.CreateTime,
		"updateTime":        agentInfo.UpdateTime,
		"remark":            agentInfo.Remark,
		"parentAgentId":     agentInfo.ParentAgentId,
		"level":             agentInfo.Level,
		"commissionRate":    agentInfo.CommissionRate,
		"settlementCycle":   agentInfo.SettlementCycle,
		"minSettleAmount":   agentInfo.MinSettleAmount,
		"maxDailyAmount":    agentInfo.MaxDailyAmount,
		"maxMonthlyAmount":  agentInfo.MaxMonthlyAmount,
		"allowedPayTypes":   agentInfo.AllowedPayTypes,
		"notifyUrl":         agentInfo.NotifyUrl,
		"whitelistIps":      agentInfo.WhitelistIps,
		"apiKey":            agentInfo.ApiKey,
		"secretKey":         agentInfo.SecretKey,
		"certPath":          agentInfo.CertPath,
		"privateKeyPath":    agentInfo.PrivateKeyPath,
		"isTestMode":        agentInfo.IsTestMode,
		"autoSettle":        agentInfo.AutoSettle,
		"riskControlLevel":  agentInfo.RiskControlLevel,
		"businessLicense":   agentInfo.BusinessLicense,
		"legalPerson":       agentInfo.LegalPerson,
		"bankAccount":       agentInfo.BankAccount,
		"bankName":          agentInfo.BankName,
		"accountHolder":     agentInfo.AccountHolder,
	}
}

// Legacy functions for backward compatibility
// These functions maintain the original API while using the new service internally

// AgentAdminCreate creates a new agent (legacy function)
func AgentAdminCreate(ctx context.Context, input *AgentAdminCreateInput) (*AgentInfo, error) {
	client, err := NewClient(&Config{
		BaseURL:  input.Baseurl,
		Username: input.Username,
		Key:      input.Key,
		Timeout:  30000000000, // 30 seconds
	})
	if err != nil {
		return nil, err
	}

	service := NewAgentService(client)
	return service.CreateAgent(ctx, input.Secret, input.AgentInfo)
}

// AgentAdminUpdate updates an existing agent (legacy function)
func AgentAdminUpdate(ctx context.Context, input *AgentAdminUpdateInput) error {
	client, err := NewClient(&Config{
		BaseURL:  input.Baseurl,
		Username: input.Username,
		Key:      input.Key,
		Timeout:  30000000000, // 30 seconds
	})
	if err != nil {
		return err
	}

	service := NewAgentService(client)
	return service.UpdateAgent(ctx, input.Secret, input.AgentInfo)
}

// AgentAdminGet retrieves agent information (legacy function)
func AgentAdminGet(ctx context.Context, input *AgentAdminGetInput) (*AgentInfo, error) {
	client, err := NewClient(&Config{
		BaseURL:  input.Baseurl,
		Username: input.Username,
		Key:      input.Key,
		Timeout:  30000000000, // 30 seconds
	})
	if err != nil {
		return nil, err
	}

	service := NewAgentService(client)
	return service.GetAgent(ctx, input.Secret, input.AgentId)
}